using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;

namespace AdvancedInspector
{
	[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field)]
	public class InspectAttribute : Attribute, IRuntimeAttribute, IRuntimeAttribute<bool>
	{
		public delegate bool InspectDelegate();

		private InspectorLevel level;

		private bool condition = true;

		private int priority;

		private string methodName = string.Empty;

		private List<Delegate> delegates = new List<Delegate>();

		public InspectorLevel Level
		{
			get
			{
				return level;
			}
			set
			{
				level = value;
			}
		}

		public bool Condition
		{
			get
			{
				return condition;
			}
			set
			{
				condition = value;
			}
		}

		public int Priority
		{
			get
			{
				return priority;
			}
			set
			{
				priority = value;
			}
		}

		public string MethodName
		{
			get
			{
				return methodName;
			}
			set
			{
				methodName = value;
			}
		}

		public Type Template
		{
			get
			{
				return typeof(InspectDelegate);
			}
		}

		public List<Delegate> Delegates
		{
			get
			{
				return delegates;
			}
			set
			{
				delegates = value;
			}
		}

		public InspectAttribute()
			: this(InspectorLevel.Basic, string.Empty, true, 0)
		{
		}

		public InspectAttribute(int priority)
			: this(InspectorLevel.Basic, string.Empty, true, priority)
		{
		}

		public InspectAttribute(InspectorLevel level)
			: this(level, string.Empty, true, 0)
		{
		}

		public InspectAttribute(InspectorLevel level, int priority)
			: this(level, string.Empty, true, priority)
		{
		}

		public InspectAttribute(InspectorLevel level, string methodName)
			: this(level, methodName, true, 0)
		{
		}

		public InspectAttribute(InspectorLevel level, string methodName, int priority)
			: this(level, methodName, true, priority)
		{
		}

		public InspectAttribute(InspectorLevel level, string methodName, bool condition)
			: this(level, methodName, condition, 0)
		{
		}

		public InspectAttribute(string methodName)
			: this(InspectorLevel.Basic, methodName, true, 0)
		{
		}

		public InspectAttribute(string methodName, int priority)
			: this(InspectorLevel.Basic, methodName, true, priority)
		{
		}

		public InspectAttribute(string methodName, bool condition)
			: this(InspectorLevel.Basic, methodName, condition, 0)
		{
		}

		public InspectAttribute(string methodName, bool condition, int priority)
			: this(InspectorLevel.Basic, methodName, condition, priority)
		{
		}

		public InspectAttribute(InspectorLevel level, string methodName, bool condition, int priority)
		{
			this.level = level;
			this.condition = condition;
			this.methodName = methodName;
			this.priority = priority;
		}

		public InspectAttribute(Delegate method)
			: this(InspectorLevel.Basic, method, true, 0)
		{
		}

		public InspectAttribute(Delegate method, int priority)
			: this(InspectorLevel.Basic, method, true, priority)
		{
		}

		public InspectAttribute(Delegate method, bool condition)
			: this(InspectorLevel.Basic, method, condition, 0)
		{
		}

		public InspectAttribute(Delegate method, bool condition, int priority)
			: this(InspectorLevel.Basic, method, condition, priority)
		{
		}

		public InspectAttribute(InspectorLevel level, Delegate method)
			: this(level, method, true, 0)
		{
		}

		public InspectAttribute(InspectorLevel level, Delegate method, int priority)
			: this(level, method, true, priority)
		{
		}

		public InspectAttribute(InspectorLevel level, Delegate method, bool condition, int priority)
		{
			this.level = level;
			this.condition = condition;
			this.priority = priority;
			delegates.Add(method);
		}

		public bool Invoke(int index)
		{
			if (delegates.Count == 0 || index >= delegates.Count)
			{
				return true;
			}
			try
			{
				return (bool)delegates[index].DynamicInvoke();
			}
			catch (Exception innerException)
			{
				if (innerException is TargetInvocationException)
				{
					innerException = ((TargetInvocationException)innerException).InnerException;
				}
				Debug.LogError(string.Format("Invoking a method to retrieve a Inspect attribute failed. The exception was \"{0}\".", innerException.Message));
				return true;
			}
		}
	}
}
